#include <iostream>
#include <array>
using namespace std;

// 02:45-03:28 讲的是继承

// int main()
//{
//	array<int, 10> a1;
//	cout << sizeof(a1);
//	cout << endl;
//
//	string a3[10];
//	cout << sizeof(a3);
//
//	return 0;
// }

// 日期类 后面可能会用到
class Date
{
public:
    Date(int year = 1900, int month = 1, int day = 1)
        : _year(year), _month(month), _day(day)
    {
    }
    bool operator<(const Date &d) const
    {
        return (_year < d._year) ||
               (_year == d._year && _month < d._month) ||
               (_year == d._year && _month == d._month && _day < d._day);
    }
    bool operator>(const Date &d) const
    {
        return (_year > d._year) ||
               (_year == d._year && _month > d._month) ||
               (_year == d._year && _month == d._month && _day > d._day);
    }

    friend ostream &operator<<(ostream &_cout, const Date &d);

private:
    int _year;
    int _month;
    int _day;
};
// 重载日期类的 <<流体取
ostream &operator<<(ostream &_cout, const Date &d)
{
    _cout << d._year << "-" << d._month << "-" << d._day;
    return _cout;
}

// 函数模板 -- 参数匹配
template <class T>
bool Less(T left, T right)
{
    return left < right;
}
// 对Less函数模板进行特化
// template<>
// bool Less<Date*>(Date* left, Date* right)
//{
//	return *left < *right;
// }

// 不用特化也可以下面这样——普通函数的重载
// 复习：普通函数的重载是指在同一作用域中定义多个具有相同名称但参数列表不同的函数。C++ 会根据调用时提供的参数自动选择最匹配的重载版本。
bool Less(Date *left, Date *right)
{
    return *left < *right;
}

// int main()
//{
//	cout << Less(1, 2) << endl; // 可以比较，结果正确
//	Date d1(2022, 7, 7);
//	Date d2(2022, 7, 8);
//	cout << Less(d1, d2) << endl; // 可以比较，结果正确
//	Date* p1 = &d1;
//	Date* p2 = &d2;
//	cout << Less(p1, p2) << endl; // 可以比较，结果错误
//	return 0;
// }

// 基础模板类
template <class T1, class T2>
class Data
{
public:
    Data() { cout << "Data<T1, T2>" << endl; }
};

// 全特化1
template <>
class Data<int, char>
{
public:
    Data() { cout << "Data<int, char>" << endl; }

private:
    int _d1;
    char _d2;
};

// 全特化2
template <>
class Data<int, int>
{
public:
    Data() { cout << "Data<int, int>" << endl; }

private:
};

// 偏特化示例1：特化部分参数
template <class T1>
class Data<T1, int>
{
public:
    Data() { cout << "DaTa<T1,int>" << endl; }

private:
    T1 _d1;
    int _d2;
};

// 偏特化示例2：对参数类型进行一定限制
template <class T1, class T2>
class Data<T1 *, T2 *>
{
public:
    Data() { cout << "Data<T1*, T2*>" << endl; }
};

// int main()
//{
//	Data<int, int> d1;
//	Data<int, char> d2;
//	Data<char, int> d3;
//	Data<char*, int*> d4;
//	Data<int*, int*> d5;
//	return 0;
// }

// 既能全特化也能偏特化—— 就匹配全特化了

// 模板的特化：本质是一种参数匹配
// 匹配顺序： 全特化->偏特化-> 原模板

template <class T>
class less
{
public:
    bool operator()(const T &x, const T &y)
    {
        return x < y;
    }
};

// 偏特化
// template<class T>
// class less<T*>
//{
// public:
//	bool operator()(const T* x, const T* y)
//	{
//		return *x < *y;
//	}
// };
// 这个const修饰的是 *x  意味着函数不会修改指向的对象。

// 偏特化如下：  ——————————这种是错误的
// template<class T>
// class less<T*>
//{
// public:
//	bool operator()(const T*& x, const T*& y)
//	{
//		return *x < *y;
//	}
// };
// const T*& 表示对 const T* 类型的引用，这意味着它接受一个指向 T 类型常量的指针的引用。
//
// 复杂性：引用指针的引用增加了不必要的复杂性，使得代码难以理解和维护。
// 不直观：通常，比较操作只需要指针本身，而不需要引用指针的引用。这种实现方式显得不直观。
// 编译错误或未定义行为：使用 const T*& 在某些情况下可能会导致编译错误，特别是在模板参数匹配和类型推导时。这是因为引用的引用并不是常见的用法，容易引起编译器的混淆。

// 这种可以   但是没必要 太复杂了
// template<class T>
// class less<T*>
//{
// public:
//	bool operator()(const T*const & x, const T*const & y)
//	{
//		return *x < *y;
//	}
// };
// 详细解释
// 1. const T* const& 参数类型
// const T * ：表示指向 T 类型常量的指针，即 T 类型的对象不能通过这个指针被修改。
// const& ：表示对 const T * 类型的常量引用，即指针本身不能被修改。
// 这种声明意味着我们接受一个指向 T 类型常量的指针的常量引用。这确保了：
//
// 指针指向的对象是常量：不能通过指针修改对象。
// 指针本身是常量：不能修改指针的值。
// 2. 类型转换问题
// 引用临时变量：使用 const T* const& 可以安全地绑定到临时变量。例如，临时指针对象可以安全地传递给这个函数，因为常量引用延长了临时对象的生命周期，直到函数调用结束。
// 避免不必要的拷贝：使用引用避免了传值带来的指针拷贝，直接操作引用提高了效率。

// 3 模板分离编译

// a.h
template <class T>
T Add(const T &left, const T &right);
// a.cpp
template <class T>
T Add(const T &left, const T &right)
{
    return left + right;
}
// main.cpp
// #include"a.h"
// int main()
//{
//	Add(1, 2);
//	Add(1.0, 2.0);
//	return 0;
//}

// 为什么运行不了？详细讲解

// 你的代码不能运行的原因是因为模板函数的实现和声明在不同的文件中分开了，这在模板编程中会导致链接错误。模板的定义和实现通常需要放在同一个头文件中，以便在每个使用模板的翻译单元中都能看到模板的实现。下面详细讲解原因和解决方法。
//
// 原因解释
// 模板的编译和链接过程与普通函数不同。对于模板函数，编译器需要在编译每个翻译单元时都能看到模板的实现，因为模板的实例化是在编译时完成的。将模板的实现放在源文件中（如 a.cpp），在编译 main.cpp 时，编译器无法看到模板的实现，因此会导致链接错误。
//
// 解决方法
// 将模板函数的实现放在头文件中
// 使用显式实例化（不推荐，较少使用）
// 方法一：将模板函数的实现放在头文件中
// 这是最常用的方法，将模板函数的实现和声明放在同一个头文件中。
//
//// a.h
// #ifndef A_H
// #define A_H
//
// template<class T>
// T Add(const T& left, const T& right)
//{
//	return left + right;
// }
//
// #endif // A_H
//// main.cpp
// #include "a.h"
// int main()
//{
//	Add(1, 2);
//	Add(1.0, 2.0);
//	return 0;
// }
//
//
//
//
// 方法二：使用显式实例化声明和定义（不推荐）
// 在头文件中进行显式声明，在源文件中进行显式定义。这种方法较少使用，且不适合泛型代码的场景。
//
//// a.h
// #ifndef A_H
// #define A_H
//
// template<class T>
// T Add(const T& left, const T& right);
//
//// 显式声明
// extern template int Add<int>(const int&, const int&);
// extern template double Add<double>(const double&, const double&);
//
// #endif // A_H
//
//// a.cpp
// #include "a.h"
//
// template<class T>
// T Add(const T& left, const T& right)
//{
//	return left + right;
// }
//
//// 显式定义
// template int Add<int>(const int&, const int&);
// template double Add<double>(const double&, const double&);
//
//
//// main.cpp
// #include "a.h"
//
// int main()
//{
//	Add(1, 2);
//	Add(1.0, 2.0);
//	return 0;
// }
//
//
// 详细解释
// 模板的编译过程
// 声明阶段：在头文件中声明模板，使得其他翻译单元可以看到模板声明。
// 定义阶段：模板函数的实现（定义）必须在每个使用该模板的翻译单元中可见。
// 实例化阶段：编译器在编译每个使用模板的地方时，实例化模板。实例化过程需要模板定义在当前翻译单元中可见。
// 链接错误的原因
// 如果模板函数的实现（定义）仅存在于源文件中（如 a.cpp），则在编译其他包含头文件的翻译单元（如 main.cpp）时，编译器无法看到模板函数的实现，导致链接阶段找不到模板函数的定义，产生链接错误。
//
// 通过将模板函数的实现放在头文件中，确保在编译每个翻译单元时，编译器都能看到模板函数的定义，从而避免链接错误。

// 继承

//.

class Person
{
public:
    void Print()
    {
        cout << "name:" << _name << endl;
        cout << "age:" << _age << endl;
    }

protected:
    // private:
    string _name = "peter"; // 姓名
    int _age = 18;          // 年龄
};

class Student : public Person
{
public:
    void func()
    {
        cout << _name << endl;
        // cout << _age << endl;
    }

protected:
    int _stuid; // 学号
};

class Teacher : public Person
{
protected:
    int _jobid; // 工号
};

int main()
{
    Student s;
    s.Print();

    Teacher t;
    t.Print();

    return 0;
}
